package com.water.waterojcodesandbox.codesandbox;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.water.waterojcodesandbox.model.ExecuteCodeRequest;
import com.water.waterojcodesandbox.model.ExecuteCodeResponse;
import com.water.waterojcodesandbox.model.ExecuteMessage;
import com.water.waterojcodesandbox.utils.ProcessUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.UUID;

/**
 * Java 原生代码沙箱实现（直接复用模板方法）
 */
@Component
@Slf4j
public class JavaNativeCodeSandbox extends JavaCodeSandboxTemplate {

    private static final String GLOBAL_CODE_DIR_NAME = "tmpCode";

    private static final String GLOBAL_JAVA_CLASS_NAME = "Main.java";

    private static final String SECURITY_MANAGER = "MySecurityManager.java";

    public static final String SET_SECURITY_MANAGER = "System.setSecurityManager(new MySecurityManager());";

    @Override
    public ExecuteCodeResponse executeCode(ExecuteCodeRequest executeCodeRequest) {
        return super.executeCode(executeCodeRequest);
    }

    @Override
    public File saveCodeToFile(String code) {
        char searchChar = '{';
        String searchMain = "public static void main";

        int index = code.indexOf(searchMain); // 找到main方法
        if (index != -1) {
            index = StrUtil.indexOf(code, searchChar, index + 1); // 找main方法后第一个{
            if (index != -1) {
                StringBuilder codeBuilder = new StringBuilder(code);
                codeBuilder.insert(index + 1,SET_SECURITY_MANAGER);
                code = codeBuilder.toString();
            } else {
                throw new RuntimeException("格式错误，main方法异常");
            }
        } else {
            throw new RuntimeException("格式错误，不存在main方法");
        }

        String userDir = System.getProperty("user.dir");
        String globalCodePathName = userDir + File.separator + GLOBAL_CODE_DIR_NAME;
        log.info("文件目录:" + globalCodePathName);
        String mySecurityManagerPathName = globalCodePathName + File.separator + SECURITY_MANAGER;
        String mySecurityManagerCode = FileUtil.readString(mySecurityManagerPathName, "UTF-8");
        // 1. 判断全局代码目录是否存在，没有则新建
        if (!FileUtil.exist(globalCodePathName)) {
            FileUtil.mkdir(globalCodePathName);
        }
        // 2. 把用户的代码隔离存放,并加入安全管理器到同目录下
        String userCodeParentPath = globalCodePathName + File.separator + UUID.randomUUID();
        String userCodePath = userCodeParentPath + File.separator + GLOBAL_JAVA_CLASS_NAME;
        String securityManagerCodePath = userCodeParentPath + File.separator + SECURITY_MANAGER;

        FileUtil.touch(userCodePath);
        FileUtil.touch(securityManagerCodePath);
        log.info("需要编译的文件名: " + userCodePath);
        File securityManagerCodeFile = FileUtil.writeString(mySecurityManagerCode, securityManagerCodePath, StandardCharsets.UTF_8);
        File userCodeFile = FileUtil.writeString(code, userCodePath, StandardCharsets.UTF_8);
        return userCodeFile;
    }

    @Override
    public ExecuteMessage compileFile(File userCodeFile) throws Exception {
        String compilePath =  userCodeFile.getParentFile().getAbsolutePath() + File.separator + "*.java";
        String compileCmd = String.format("javac -encoding utf-8 %s", compilePath);
        Process compileProcess = Runtime.getRuntime().exec(compileCmd);
        ExecuteMessage executeMessage = ProcessUtils.runProcessAndGetMessage(compileProcess, "编译");
        return executeMessage;
    }
}
